﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Timers;


namespace RemoteUser
{
    public partial class PLCConnInfoForm : Form
    {
        #region 内部的变量
        private NetworkStream myStream;
        private Socket mySocket;
        private string myID;
        private string PLCID;
        private string PLCName;
        private string abnormalInfoStartTime;
        private string abnormalInfoEndTime;
        //为了调用列表窗口内的public成员和方法
        private PLCListForm myFatherForm;
        //保存远程桌面原来的界面风格。
        private uint originalStyle;
        //保存已打开的远程桌面进程对象，内含进程号，句柄等
        private static Process remoteDesktopProcess;
        public delegate void RemoteDesktop(Process remoteDesktopProcess);
        public delegate void RemoteDesktopButtonEnable();
        public delegate void ModifyPLCConnInfo(string newPLCConnInfo);
        public delegate void ModifyUserInfo(object localUserInfo,object remoteUserInfo);
        public delegate void ModifyKeyParms(object produceCraftsKeyParms, object deviceStatusKeyParms, string produceCraftsknowledgeInfo,string deviceStatusknowledgeInfo);
        private System.Timers.Timer startOrStopTimer;
        //远程桌面是否已弹出
        private bool isPoped = false;
        //根据程序是否结束判断
        public bool processIsRunning = false;
        //在远程桌面弹出后，保持其窗口状态可拖动，1S设定一次
        Thread checkThePopedMstscThread;
        #endregion
        public PLCConnInfoForm()
        {
            InitializeComponent();
        }
        //重载的构造函数
        public PLCConnInfoForm(NetworkStream netstream, 
                                Socket clientSocket, 
                                string ID, 
                                string selectedPLCID,
                                string selectedPLCName,
                                PLCListForm PLCListViewForm)
        { 
            InitializeComponent();
            myStream = netstream;
            mySocket = clientSocket;
            myID = ID;
            PLCID = selectedPLCID;
            PLCName = selectedPLCName;
            PLCNameLabel.Text = "PLC名称: "+ selectedPLCName;           
            PLCIDLabel.Text = "PLCID:   " + selectedPLCID;
            myFatherForm = PLCListViewForm;
            this.Closing += new CancelEventHandler(PLCConnInfoForm_FormClosing);
            this.popRemoteDesktopButton.Enabled = false;
        }

        private void PLCConnInfoForm_Load(object sender, EventArgs e)
        {
            SendAndRecv.SendPLCConnInfoRequest(myStream, myID, PLCID);
            SendAndRecv.SendPLCKeyParmsRequest(myStream, myID, PLCID);
            startOrStopTimerMonitorButton.Enabled = false;
            //到达时间的时候执行事件,周期为5秒；
            startOrStopTimer = new System.Timers.Timer(5 * 1000);
            //这里不要定义变量！
            startOrStopTimer.Elapsed += new System.Timers.ElapsedEventHandler(StartMonitor);
            startOrStopTimer.AutoReset = true;  //设置一直执行(true)
            startOrStopTimer.Enabled = true;    //是否执行System.Timers.Timer.Elapsed事件
            startOrStopTimerMonitorButton.Enabled = true;
            detaileAbnormalInfoButton.Enabled = false;
            endDateTimePicker.Enabled = false;
        }
        /// <summary>
        /// 全部参数请求。并且生成全部参数界面。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AllParmsButton_Click(object sender, EventArgs e)
        {
            SendAndRecv.SendPLCAllParmsRequest(myStream, myID, PLCID);
            myFatherForm.CreatePLCAllParmsForm();
        }
        /// <summary>
        /// 关闭按钮点击触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PLCConnInfoForm_FormClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
                myFatherForm.PLCConnInfoFormIsExisted = false;
                startOrStopTimer.Enabled = false;
                //此时将远程桌面一并关闭
                if (processIsRunning)
                    remoteDesktopProcess.Kill();
                this.Owner.Show();
                //一定会关闭此窗口
                e.Cancel = false;
        }
        /// <summary>
        /// 远程桌面按钮。未启动程序时是“远程桌面”，启动后是“关闭远程桌面”。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void remoteDesktopButton_Click(object sender, EventArgs e)
        {
            if (!processIsRunning)
            {
                this.remoteDesktopButton.Enabled = false;
                SendAndRecv.SendRemoteDesktopRequest(myStream, myID, PLCID);
                this.remoteDesktopButton.Text = "关闭远程桌面";
                this.popRemoteDesktopButton.Enabled = true;
            }
            else
            { 
                remoteDesktopProcess.Kill();
                this.remoteDesktopButton.Text = "远程桌面";
                this.popRemoteDesktopButton.Enabled = false;
                this.RemoteInfoTextBox.Text = "";
            }
        }
        /// <summary>
        /// 修改远程桌面按钮的可用性，供PLC列表界面调用。
        /// </summary>
        public void ModifyTheRemoteDesktopButtonEnable()
        {
            this.remoteDesktopButton.Enabled = true;
        }
        /// <summary>
        /// 显示PLC联系信息（公司），供PLC列表窗口调用
        /// </summary>
        /// <param name="newInfo"></param>
        public void ModifyPLCConnInfoRichTextBox(string newInfo)
        {
            this.companyInfoRichTextBox.Text = newInfo;
        }
        /// <summary>
        /// 显示远程桌面需要的用户名密码，供PLC列表窗口调用
        /// </summary>
        /// <param name="remoteUserName"></param>
        /// <param name="remoteUserPwd"></param>
        public void ModifyRemoteInfoTextBox(string remoteUserName,string remoteUserPwd)
        {
            this.RemoteInfoTextBox.Text = "用户名：" + remoteUserName + "\n" + "密  码：" + remoteUserPwd;
        }
        /// <summary>
        /// ****嵌入远程桌面
        /// ****需要程序已运行，并置弹出标志ispoped为false
        /// ****此处的异常暂时无法解决，不影响运行
        /// </summary>
        /// <param name="remoteDesktop"></param>
        public void EmbedRemoteDesktop(Process remoteDesktop)
        {
            if (processIsRunning)
            {
                IntPtr handle = remoteDesktop.MainWindowHandle;
                SetParent(handle, this.Handle);
                originalStyle = GetWindowLong(handle, GWL_STYLE);
                try
                {
                    SetWindowLong(handle, GWL_STYLE, WS_VISIBLE);
                }
                catch
                { }
                finally
                {
                    MoveWindow(handle, 0, 100, 600, 480, true);
                    SetForegroundWindow(handle);
                    isPoped = false;
                    remoteDesktopProcess = remoteDesktop;
                }
            }
            else
                MessageBox.Show("远程桌面尚未执行");
          //  MoveWindow(handle, 0, 100, 400, 300, true);
        }
        /// <summary>
        /// ****弹出远程桌面窗口，并开启线程，维护该窗口标题栏可用。
        /// ****需要远程桌面程序运行，ispoped标志位置true
        /// ****此处异常不影响运行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PopRemoteDesktopButton_Click(object sender, EventArgs e)
        {   
            //判斷一下確定嵌入還是彈出
            //修改按钮文字待做
            IntPtr handle = default(IntPtr);
            IntPtr hDesktop = default(IntPtr);
            if (processIsRunning)
            {
                if (!isPoped)
                {
                    handle = remoteDesktopProcess.MainWindowHandle;
                    hDesktop = FindWindow("Progman", null);//获取系统句柄
                    hDesktop = GetWindow(hDesktop, GW_CHILD);//获取其子窗口句柄，就是桌面的句柄
                    SetParent(handle, hDesktop);
                    SetWindowLong(handle, GWL_STYLE, originalStyle);//恢复原来的带有标题栏的风格
                    MoveWindow(handle, 0, 0, 600, 480, true);
                    SetForegroundWindow(handle);
                    isPoped = true;
                    checkThePopedMstscThread = new Thread(CheckThePopedMstsc);
                    checkThePopedMstscThread.IsBackground = true;
                    checkThePopedMstscThread.Start();
                }
                else
                {
                    //嵌入
                    EmbedRemoteDesktop(remoteDesktopProcess);
                }
            }
            else
                MessageBox.Show("远程桌面尚未执行");

        }
        /// <summary>
        /// 维护远程桌面窗口弹出后标题栏可用的线程，1s一次
        /// </summary>
        private void CheckThePopedMstsc()
        {
            //string name = "mstsc";
            while (isPoped && !remoteDesktopProcess.HasExited)
            {
                if (!IsZoomed(remoteDesktopProcess.MainWindowHandle))
                {
                    SetWindowLong(remoteDesktopProcess.MainWindowHandle, GWL_STYLE, originalStyle);
                }
                Thread.Sleep(1000);     
            }
        }
        
        private void StartMonitor(object sender, EventArgs e)
        {
            SendAndRecv.SendPLCKeyParmsRequest(myStream, myID, PLCID);
        }

        public void ModifyTheUserInfoData(object localUserInfo, object remoteUserInfo)
        {
            localUserInfoDataGridView.DataSource = (BindingCollection<RemoteAndLocalUserInfo>)localUserInfo;
            remoteUserInfoDataGridView.DataSource = (BindingCollection<RemoteAndLocalUserInfo>)remoteUserInfo;
            localUserInfoDataGridView.Refresh();
            remoteUserInfoDataGridView.Refresh();
        }

        private void localUserDataBindingComplete(object sender, 
                                                    DataGridViewBindingCompleteEventArgs e)
        {
            localUserInfoDataGridView.Columns["userName"].HeaderText = "姓名";
            localUserInfoDataGridView.Columns["tel"].HeaderText = "电话";
            localUserInfoDataGridView.Columns["email"].HeaderText = "电邮";
            localUserInfoDataGridView.Columns["type"].Visible = false;//隐藏某列：
        }
        
        private void remoteUserDataBindingComplete(object sender, 
                                                    DataGridViewBindingCompleteEventArgs e)
        {
            remoteUserInfoDataGridView.Columns["userName"].HeaderText = "姓名";
            remoteUserInfoDataGridView.Columns["tel"].HeaderText = "电话";
            remoteUserInfoDataGridView.Columns["email"].HeaderText = "电邮";
            remoteUserInfoDataGridView.Columns["type"].Visible = false;//隐藏某列：
        }

        public void ModifyKeyParmsData(object produceCraftsKeyParms,
                                        object deviceStatusKeyParms,
                                        string produceCraftsknowledgeInfo,
                                        string deviceStatusknowledgeInfo)
        {
            produceCraftsKeyParmsDataGridView.DataSource = (BindingCollection<ParmNode>)produceCraftsKeyParms;
            deviceStatusKeyParmsDataGridView.DataSource = (BindingCollection<ParmNode>)deviceStatusKeyParms;    
            produceCraftsKeyParmsDataGridView.Refresh();
            deviceStatusKeyParmsDataGridView.Refresh();
            produceCraftsknowledgeInfoTextBox.Text = produceCraftsknowledgeInfo;
            deviceStatusknowledgeInfoTextBox.Text = deviceStatusknowledgeInfo;
        }

        private void produceCraftsDataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            produceCraftsKeyParmsDataGridView.Columns["parmName"].HeaderText = "参数";
            produceCraftsKeyParmsDataGridView.Columns["parmValue"].HeaderText = "数值";
        }

        private void deviceStatusDataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            deviceStatusKeyParmsDataGridView.Columns["parmName"].HeaderText = "参数";
            deviceStatusKeyParmsDataGridView.Columns["parmValue"].HeaderText = "数值";
        }

        private void startOrStopTimerMonitorButton_Click(object sender, EventArgs e)
        {
            if (startOrStopTimer.Enabled == true)
            {
                startOrStopTimer.Enabled = false;
                startOrStopTimerMonitorButton.Text = "开始";
            }
            else
            {
                startOrStopTimer.Enabled = true;
                startOrStopTimerMonitorButton.Text = "暂停";
            }
        }

        private void detaileAbnormalInfoButton_Click(object sender, EventArgs e)
        {
            if (abnormalInfoStartTime == null)
                abnormalInfoStartTime = DateTime.Now.ToString();
            if (abnormalInfoEndTime == null)
                abnormalInfoEndTime = DateTime.Now.ToString();
            myFatherForm.CreatePLCAbnormalInfoForm(abnormalInfoStartTime, abnormalInfoEndTime);
        }

        private void startDateTimePicker_ValueChanged(object sender, EventArgs e)
        {
            abnormalInfoStartTime = startDateTimePicker.Value.ToString();
            detaileAbnormalInfoButton.Enabled = true;
            endDateTimePicker.Enabled = true;
            endDateTimePicker.MinDate = startDateTimePicker.Value;
        }

        private void endDateTimePicker_ValueChanged(object sender, EventArgs e)
        {
            abnormalInfoEndTime = endDateTimePicker.Value.ToString();
            startDateTimePicker.MaxDate = endDateTimePicker.Value;
        }
        
        #region WinAPI系统调用
        [DllImport("user32.dll", SetLastError = true)]
        private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
        private static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong);

        [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
        private static extern uint GetWindowLong(IntPtr hwnd, int nIndex);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", EntryPoint = "GetWindow")]//获取窗体句柄，hwnd为源窗口句柄
        public static extern IntPtr GetWindow(IntPtr hwnd, int wCmd);

        [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        
        [DllImport("user32.dll", EntryPoint = "PostMessageA")]
        public static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll")]
        private static extern bool IsIconic(IntPtr hWnd);

        [DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern bool IsZoomed(IntPtr hWnd);

        public const int WM_SYSCOMMAND = 0x0112;
        public const int SC_MAXIMIZE = 0xF030;
        public const int SC_DRAGMOVE = 0xF012;
        public const int WM_LBUTTONDOWN = 0x0201;
        public const int SC_MOVE = 0xf010;
        public const int HTCAPTION = 0x0002;
        private const int GW_CHILD = 5;
        private const int GWL_STYLE = (-16);
        private const uint WS_VISIBLE = 0x10000000;
        #endregion



    }
}
